package com.core.springaop;

import com.core.comment.ConfigUtil;
import com.core.spring.DefaultMyApplication;
import com.core.spring.IocBeanFactory;
import com.core.springaop.annotate.MyAfter;
import com.core.springaop.annotate.MyAscept;
import com.core.springaop.annotate.MyBefor;

import java.io.File;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

public class MyAopFactory<T> {
    private List<String> classNames = new LinkedList<>();
    private static MyAopFactory myAopFactory = null;

    public static void getInstance() {
        if (myAopFactory == null) {
            myAopFactory = new MyAopFactory();
            myAopFactory.init();
        }

    }

    /**
     * 代理执行clazz
     *
     * @param clazz 被代理类
     * @param <T>
     * @return 被代理类实体
     */
    public static <T> T getSub(Class<?> clazz) {
        try {
            if (clazz.isInterface()) {
                return null;
            }
            Object o = null;
            //优先使用jdk动态代理
            // 规则：1.如果clazz有接口则用jdk动态代理（执行的方法必须接口里定义）2.否则直接用cgli代理
            if (clazz.getInterfaces().length > 0) {
                MyJdkHandle.getSelf().setObject(clazz.newInstance());
                o = Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), MyJdkHandle.getSelf());

            }
            if (o == null || clazz.getInterfaces().length == 0) {
                return (T) MyCglibHandle.getSelf().getInstance(clazz);
            } else {
                return (T) o;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 初始化扫描所有切面配置
     */
    private void init() {
        List<Class> aopClassList = ((DefaultMyApplication) IocBeanFactory.getInstant()).getAopClassList();
        try {
            if (aopClassList.isEmpty()) {
                return;
            }
            for (Class<?> clazz : aopClassList) {
                if (clazz.isAnnotationPresent(MyAscept.class)) {
                    MyAscept ascept = clazz.getAnnotation(MyAscept.class);
                    String cut = ascept.value();
                    Object o = clazz.newInstance();
                    for (Method m : clazz.getMethods()) {
                        MyBefor befor = m.getAnnotation(MyBefor.class);
                        if (befor != null) {
                            Point p = new Point();
                            p.setCut(cut);
                            p.setMethod(m);
                            p.setType("befor");
                            p.setClazz(clazz);
                            p.setAscept(o);
                            MyAopCache.putbefor(cut, p);
                        }

                        MyAfter after = m.getAnnotation(MyAfter.class);
                        if (after != null) {
                            Point p = new Point();
                            p.setCut(cut);
                            p.setMethod(m);
                            p.setType("after");
                            p.setClazz(clazz);
                            p.setAscept(o);
                            MyAopCache.putafter(cut, p);
                        }
                    }
                }

            }


        } catch (Exception e) {
            e.printStackTrace();
        }

        aopClassList = null;
    }

    private void scanProxy() {
        if (classNames.isEmpty()) {
            return;
        }
        try {
            Set<String> cutSet1 = MyAopCache.getBeferAop().keySet();
            Set<String> cutSet2 = MyAopCache.getAfterAop().keySet();

            for (String name : classNames) {
                Class<?> clazz = Class.forName(name);
                for (String cut : cutSet1) {
                    if (MyJdkHandle.ismatchExpressClass(clazz, cut)) {
                        MyAopCache.addSet(name);
                    }
                }

                for (String cut : cutSet2) {
                    if (MyJdkHandle.ismatchExpressClass(clazz, cut)) {
                        MyAopCache.addSet(name);
                    }
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


}
